home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / manchest.lha / MANCHESTER / usenet / st80_pre4 / bos.st < prev    next >
Text File  |  1993-07-24  |  21KB  |  724 lines

  1. "    NAME        bos
  2.     AUTHOR        eliot@cs.qmc.ac.uk (Eliot Miranda)
  3.     FUNCTION save&restore binaries 
  4.     ST-VERSIONS    B2.3
  5.     PREREQUISITES     
  6.     CONFLICTS    
  7.     DISTRIBUTION      world
  8.     VERSION        1.1
  9.     DATE    26 Sep 1989
  10. "
  11. !
  12. "
  13.  
  14.         Binary Structure Copying.
  15.  
  16.         E. Miranda. QMC 31 July 1989.
  17.  
  18. This package allows one to store and retreive arbitrary networks of
  19. Smalltalk objects to and from files.  The package copes with circular
  20. structures and with structures of arbitrary size.  Objects are stored
  21. on files in a binary representation giving improved performance over
  22. the textual ''structure copying'' system which it supercedes.
  23.  
  24.     To store an object (& its contents) use
  25.  
  26.         anObject storeBinary
  27.         anObject storeBinaryOn: 'myfile.stbin'
  28.  
  29.     To retreive an object use
  30.  
  31.         BinaryInputManager readFrom: 'myfile.stbin'
  32.  
  33. Use of the file suffix '.stbin' is strongly recommended for binary files
  34. created with this package.
  35.  
  36. From: eliot@cs.qmc.ac.uk (Eliot Miranda)
  37. Newsgroups: comp.lang.smalltalk
  38. Subject: Binary Object Storage in Smalltalk-80
  39. Message-ID: <1173@sequent.cs.qmc.ac.uk>
  40. Date: 31 Jul 89 14:32:20 GMT
  41. Organization: CS Dept, Queen Mary College, University of London, UK.
  42.  
  43. Here is a Smalltalk-80 package to save + restore arbitrary objects to + from
  44. files.  A description follows below.  But first some notes on the code.
  45. The system was written for QMC's version of Smalltalk-80 2.3 which is very like
  46. ParcPlace Smalltalk-80 V2.3 with some exceptions:
  47.  
  48. QMC's version
  49.     a) permits temporaries to be declared in blocks
  50.     b) has a class variable in Form called SystemIsBigEndian
  51.  
  52. If you're filing this in on a Smalltalk without block temporaries you'll need to
  53. correct the code. e.g.
  54.  
  55.     store: anObject on: aStream
  56.         | manager |
  57.         Cursor wait showWhile: [manager _ (self new: 1024) initialize].
  58.         Cursor write showWhile: [
  59.             (aStream isKindOf: String)
  60.                 ifTrue: [
  61.                     | fileStream |
  62.                     fileStream _ FileStream fileNamed: aStream.
  63.  
  64. must be changed to
  65.  
  66.     store: anObject on: aStream
  67.         | manager fileStream |
  68.         Cursor wait showWhile: [manager _ (self new: 1024) initialize].
  69.         Cursor write showWhile: [
  70.             (aStream isKindOf: String)
  71.                 ifTrue: [
  72.                     fileStream _ FileStream fileNamed: aStream.
  73.  
  74.  
  75. Hopefully someone will be able to adapt this for Smalltalk-V (if needed).
  76. I place NO restrictions on the use of this code.
  77.  
  78. Here it is; Share And Enjoy!!
  79.  
  80. Eliot Miranda                email:        eliot@cs.qmc.ac.uk
  81. Dept of Computer Science        Tel:        01 975 5220
  82. Queen Mary College            International:    +44 1 975 5220
  83. Mile End Road
  84. LONDON E1 4NS
  85.  
  86. "
  87. !
  88.  
  89. IdentityDictionary variableSubclass: #BinaryIOManager
  90.     instanceVariableNames: ''
  91.     classVariableNames: 'ClassType FalseType GlobalType IdType NilType ObjectType TrueType TypeTable '
  92.     poolDictionaries: ''
  93.     category: 'System-Support'!
  94. BinaryIOManager comment:
  95. 'I am a shared superclass for the binary IO classes BinaryInputManager & BinaryOutputManager.
  96. I define some class variables that define the types of descriptions in binary files, see BinaryIOManager class>>initialize'!
  97.  
  98.  
  99. !BinaryIOManager methodsFor: 'accessing'!
  100.  
  101. codeForFalse
  102.     ^FalseType!
  103.  
  104. codeForNil
  105.     ^NilType!
  106.  
  107. codeForTrue
  108.     ^TrueType! !
  109.  
  110. !BinaryIOManager methodsFor: 'adding'!
  111.  
  112. grow
  113.     "Must copy instance variables when growing"
  114.     | instVars |
  115.     instVars _ (self class superclass instSize + 1 to: self class instSize) collect: [:i|
  116.                     Association key: i value: (self instVarAt: i)].
  117.     super grow.
  118.     instVars do: [:assoc| self instVarAt: (assoc key) put: assoc value]! !
  119.  
  120. !BinaryIOManager methodsFor: 'private'!
  121.  
  122. rehash
  123.     "Must copy instance variables when rehashing"
  124.     | instVars |
  125.     instVars _ (self class superclass instSize + 1 to: self class instSize) collect: [:i|
  126.                     Association key: i value: (self instVarAt: i)].
  127.     super rehash.
  128.     instVars do: [:assoc| self instVarAt: (assoc key) put: assoc value]! !
  129. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  130.  
  131. BinaryIOManager class
  132.     instanceVariableNames: ''!
  133.  
  134.  
  135. !BinaryIOManager class methodsFor: 'class initialization'!
  136.  
  137. initialize
  138.     "Initialize the types & type table for binary i/o"
  139.  
  140.     TypeTable _ #(    getObjectId
  141.                         getNil
  142.                         getTrue
  143.                         getFalse
  144.                         getObjectDefinition
  145.                         getClassDefinition
  146.                         getGlobalDefinition ).
  147.     IdType _ 1.
  148.     NilType _ 2.
  149.     TrueType _ 3.
  150.     FalseType _ 4.
  151.     ObjectType _ 5.
  152.     ClassType _ 6.
  153.     GlobalType  _ 7
  154.  
  155.     "BinaryIOManager initialize"! !
  156.  
  157. BinaryIOManager initialize!
  158.  
  159.  
  160.  
  161. !SmallInteger methodsFor: 'binary storage'!
  162.  
  163. hasSpecialBinaryRepresentation
  164.     ^true!
  165.  
  166. storeBinaryOn: stream manager: manager
  167.     "SmallIntegers are stored as their value with the 32nd bit set as a tag."
  168.  
  169.     stream
  170.         nextPut: (((self bitShift: -24) bitAnd: 16rFF) bitOr: 16r80);
  171.         nextPut: ((self bitShift: -16) bitAnd: 16rFF);
  172.         nextPut: ((self bitShift: -8) bitAnd: 16rFF);
  173.         nextPut: (self bitAnd: 16rFF)! !
  174.  
  175.  
  176. !String methodsFor: 'binary storage'!
  177.  
  178. storeBinaryDefinitionOn: stream manager: manager
  179.     manager putIdOf: self class on: stream.
  180.     stream nextNumber: 4 put: self basicSize.
  181.     stream nextPutAll: self asByteArray! !
  182.  
  183.  
  184. !Set methodsFor: 'binary storage'!
  185.  
  186. readBinaryContentsFrom: stream manager: manager
  187.     super readBinaryContentsFrom: stream manager: manager.
  188.     self rehash! !
  189.  
  190.  
  191. !TextStyle class methodsFor: 'binary storage'!
  192.  
  193. addGlobalsTo: globalDictionary manager: manager
  194.     TextStyles do: [:style|
  195.         style fontArray do: [:font|
  196.             globalDictionary at: font put: self]]!
  197.  
  198. storeBinaryDefinitionOf: anObject on: stream manager: manager
  199.     anObject class == StrikeFont ifTrue: [
  200.         TextStyles associationsDo: [:assoc|
  201.             | style |
  202.             style _ assoc value.
  203.             1 to: style fontArray size do: [:i|
  204.                 (style fontAt: i) == anObject ifTrue: [
  205.                     | string |
  206.                     string _ '(TextStyle styleNamed: ', assoc key storeString, ') fontAt: ', i printString.
  207.                     stream nextNumber: 2 put: string size.
  208.                     string do: [:char| stream nextPut: char asciiValue].
  209.                     ^self]]]].
  210.     ^super storeBinaryDefinitionOf: anObject on: stream manager: manager! !
  211.  
  212.  
  213. !ClassDescription methodsFor: 'binary storage'!
  214.  
  215. binaryDefinitionFrom: stream manager: manager
  216.     | obj basicSize i |
  217.     self isPointers ifTrue: [
  218.         stream next. "skip instSize"
  219.         ^self isVariable
  220.             ifTrue: [self basicNew: (stream nextNumber: 3)]
  221.             ifFalse: [self basicNew]].
  222.  
  223.     obj _ self basicNew: (basicSize _ stream nextNumber: 4).
  224.     i _ 0.
  225.     self isBytes
  226.         ifTrue: [
  227.             [(i _ i + 1) <= basicSize] whileTrue: [
  228.                 obj basicAt: i put: stream next]]
  229.         ifFalse: [
  230.             [(i _ i + 1) <= basicSize] whileTrue: [
  231.                 obj basicAt: i put: stream nextWord]].
  232.     ^obj!
  233.  
  234. storeBinaryDefinitionOn: stream manager: manager
  235.     | myName |
  236.     stream
  237.         nextWordPut: (format bitAnd: 16rFFFF);
  238.         nextWordPut: (myName _ self name) size.
  239.     myName do: [:c| stream nextPut: c asciiValue]! !
  240.  
  241.  
  242. !String class methodsFor: 'binary storage'!
  243.  
  244. binaryDefinitionFrom: stream manager: manager
  245.     ^(stream next: (stream nextNumber: 4)) asString! !
  246.  
  247.  
  248. !Object methodsFor: 'testing'!
  249.  
  250. isClass
  251.     ^false!
  252.  
  253. isFileStream
  254.     ^false! !
  255.  
  256. !Object methodsFor: 'public binary storage'!
  257.  
  258. storeBinary
  259.     "Writes a description of the receiver into a file, in a way that allows
  260.      the object's structure to be reconstructed from the file's contents."
  261.  
  262.     | fileName |
  263.     fileName _ FileDirectory
  264.                     requestFileName: 'Store binary on which file name?'
  265.                     default: (self class name, '.', self asOop printString, '.stbin')
  266.                     version: #any
  267.                     ifFail: [^nil].
  268.     BinaryOutputManager store: self on: fileName!
  269.  
  270. storeBinaryOn: aStream
  271.     "Writes a description of the receiver onto aStream, in a way that allows
  272.      the object's structure to be reconstructed from the stream's contents"
  273.  
  274.     BinaryOutputManager store: self on: aStream! !
  275.  
  276. !Object methodsFor: 'binary storage'!
  277.  
  278. hasSpecialBinaryRepresentation
  279.     ^false!
  280.  
  281. readBinaryContentsFrom: stream manager: manager
  282.     | size i |
  283.     size _ self class instSize.
  284.     i _ 0.
  285.     [(i _ i + 1) <= size] whileTrue: [
  286.         self instVarAt: i put: manager nextObject].
  287.     size _ self basicSize.
  288.     i _ 0.
  289.     [(i _ i + 1) <= size] whileTrue: [
  290.         self basicAt: i put: manager nextObject]!
  291.  
  292. storeBinaryDefinitionOn: stream manager: manager
  293.  
  294.     | i basicSize |
  295.     manager putIdOf: self class on: stream.
  296.     i _ 0.
  297.     self class isPointers
  298.         ifTrue: [
  299.             | instSize |
  300.             stream nextPut: (instSize _ self class instSize).
  301.             self class isVariable
  302.                 ifTrue: [stream nextNumber: 3 put: (basicSize _ self basicSize)]
  303.                 ifFalse: [basicSize _ 0].
  304.  
  305.             [(i _ i + 1) <= instSize] whileTrue: [
  306.                 manager putIdOf: (self instVarAt: i) on: stream].
  307.  
  308.             i _ 0.
  309.             [(i _ i + 1) <= basicSize] whileTrue: [
  310.                 manager putIdOf: (self basicAt: i) on: stream]]
  311.         ifFalse: [
  312.             stream nextNumber: 4 put: (basicSize _ self basicSize).
  313.             self class isBytes
  314.                 ifTrue: [
  315.                     [(i _ i + 1) <= basicSize] whileTrue: [
  316.                         stream nextPut: (self basicAt: i)]]
  317.                 ifFalse: [
  318.                     [(i _ i + 1) <= basicSize] whileTrue: [
  319.                         stream nextWordPut: (self basicAt: i)]]]!
  320.  
  321. storeBinaryOn: stream manager: manager
  322.     manager putIdOf: self on: stream! !
  323.  
  324.  
  325. !ExternalStream methodsFor: 'nonhomogeneous accessing'!
  326.  
  327. nextNumber: n 
  328.     "Answer the next n bytes as a positive Integer or LargePositiveInteger."
  329.  
  330.     | s i |
  331.     n <= 4 ifTrue: 
  332.         [s _ 0.
  333.         i _ 0.
  334.         [(i _ i + 1) <= n] whileTrue: [s _ ((s bitShift: 8) bitOr: self next)].
  335.         ^s].
  336.     s _ LargePositiveInteger new: n.
  337.     1 to: n do: [:j | s at: n + 1 - j put: self next].
  338.     "reverse order of significance"
  339.     ^s truncated!
  340.  
  341. nextNumber: n put: v 
  342.     "Append to the receiver the argument, v, which is a positive SmallInteger or
  343.     a LargePositiveInteger, as the next n bytes.  Possibly pad with leading zeros."
  344.  
  345.     | vlen i |
  346.     n < (vlen _ v digitLength) ifTrue: [self error: 'number too big'].
  347.  
  348.     "pad with leading zeros"
  349.     i _ n.
  350.     [i > vlen] whileTrue: [self nextPut: 0. i _ i - 1].
  351.     i = 1 ifTrue: [^self nextPut: v].
  352.     [i > 0] whileTrue: [self nextPut: (v digitAt: i). i _ i - 1]! !
  353.  
  354.  
  355. !SmallInteger class methodsFor: 'binary storage'!
  356.  
  357. binaryDefinitionFrom: stream manager: manager
  358.     | value |
  359.     (value _ (stream next bitAnd: 16r7F)) > 16r3F
  360.         ifTrue: [value _ value - 16r80].
  361.     value _ (value bitShift: 8) bitOr: stream next.
  362.     value _ (value bitShift: 8) bitOr: stream next.
  363.     value _ (value bitShift: 8) bitOr: stream next.
  364.     ^value! !
  365.  
  366.  
  367. !Class methodsFor: 'testing'!
  368.  
  369. isClass
  370.     ^true! !
  371.  
  372. !Class methodsFor: 'binary storage'!
  373.  
  374. addGlobalsTo: globalDictionary manager: manager
  375.     classPool == nil ifFalse: [
  376.         classPool associationsDo: [:assoc|
  377.             globalDictionary at: assoc put: self]]!
  378.  
  379. storeBinaryDefinitionOf: anAssociation on: stream manager: manager
  380.     | string | 
  381.     string _ self name, ' classPool at: ', anAssociation key storeString.
  382.     stream nextNumber: 2 put: string size.
  383.     string do: [:char| stream nextPut: char asciiValue]! !
  384.  
  385.  
  386. !Symbol class methodsFor: 'binary storage'!
  387.  
  388. binaryDefinitionFrom: stream manager: manager
  389.     ^self intern: (super binaryDefinitionFrom: stream manager: manager)! !
  390.  
  391.  
  392. !Dictionary methodsFor: 'binary storage'!
  393.  
  394. addGlobalsTo: globalDictionary manager: manager
  395.     self associationsDo: [:assoc| globalDictionary at: assoc put: self]!
  396.  
  397. storeBinaryDefinitionOf: anObject on: stream manager: manager
  398.     | string | 
  399.     string _ (Smalltalk keyAtValue: self), ' associationAt: ', anObject key storeString.
  400.     stream nextNumber: 2 put: string size.
  401.     string do: [:char| stream nextPut: char asciiValue]! !
  402.  
  403.  
  404. !Boolean methodsFor: 'binary storage'!
  405.  
  406. hasSpecialBinaryRepresentation
  407.     ^true! !
  408.  
  409.  
  410. !Form methodsFor: 'binary storage'!
  411.  
  412. readBinaryContentsFrom: stream manager: manager
  413.     "read the trailing byte containing flags to define system dependent information about the form
  414.      and respond accordingly."
  415.  
  416.     | flags |
  417.     super readBinaryContentsFrom: stream manager: manager.
  418.     flags _ stream next.
  419.  
  420.     (flags allMask: 1) ~= SystemIsBigEndian ifTrue: [    "Reverse the bits in form"
  421.         depth = 1 ifTrue: [
  422.             1 to: bits size do: [:i| bits at: i put: (bits at: i) wordReversed]]]!
  423.  
  424. storeBinaryDefinitionOn: stream manager: manager
  425.     "append a byte containing flags to define system dependent information about the form.
  426.      Currently the bits are:
  427.         bit 1:    is the system bigendian+bigbittian"
  428.  
  429.     super storeBinaryDefinitionOn: stream manager: manager.
  430.     stream nextPut: (SystemIsBigEndian ifTrue: [1] ifFalse: [0])! !
  431.  
  432.  
  433. !UndefinedObject methodsFor: 'binary storage'!
  434.  
  435. hasSpecialBinaryRepresentation
  436.     ^true!
  437.  
  438. storeBinaryOn: stream manager: manager
  439.     stream nextPut: manager codeForNil! !
  440.  
  441. BinaryIOManager variableSubclass: #BinaryInputManager
  442.     instanceVariableNames: 'stream '
  443.     classVariableNames: ''
  444.     poolDictionaries: ''
  445.     category: 'System-Support'!
  446. BinaryInputManager comment:
  447. 'I read binary files of the format created by BinaryOutputManager.  See the comment there for details of the format.  Use
  448.  
  449.     BinaryInputManager readFrom: ''filename.stbin''
  450.  
  451. to recreate the objects stored on such files.'!
  452.  
  453.  
  454. !BinaryInputManager methodsFor: 'public access'!
  455.  
  456. readFrom: aStream
  457.     (stream _ aStream) isFileStream
  458.         ifTrue: [stream binary].
  459.     ^self nextObject! !
  460.  
  461. !BinaryInputManager methodsFor: 'structure reading'!
  462.  
  463. getClassDefinition
  464.     | id format nameLength name class |
  465.     id _ stream nextNumber: 3.
  466.     format _ stream nextNumber: 2.
  467.     nameLength _ stream nextNumber: 2.
  468.     name _ (stream next: nameLength) asString.
  469.     (Symbol hasInterned: name ifTrue: [:sym| name _ sym])
  470.         ifFalse: [self error: 'Unknown class name: ', name].
  471.     class _ Smalltalk at: name ifAbsent: [self error: 'Non-existant class: ', name].
  472.     (class format bitAnd: 16rFFFF) ~= format
  473.         ifTrue: [self error: 'Class format has changed'].
  474.     self at: id put: class.
  475.     ^class!
  476.  
  477. getFalse
  478.     ^false!
  479.  
  480. getGlobalDefinition
  481.     | id nameLength object |
  482.     id _ stream nextNumber: 3.
  483.     nameLength _ stream nextNumber: 2.
  484.     object _ Cursor execute showWhile: [
  485.                     Compiler evaluate: (stream next: nameLength) asString for: nil logged: false].
  486.     ^self at: id put: object!
  487.  
  488. getNil
  489.     ^nil!
  490.  
  491. getObjectDefinition
  492.     | id class obj |
  493.     self
  494.         at: (id _ stream nextNumber: 3)
  495.         put: (obj _ (class _ self nextObject)
  496.                         binaryDefinitionFrom: stream manager: self).
  497.     "Must add the object to the table BEFORE reading the rest of its definition
  498.      because it may (even indirectly) refer to itself"
  499.     class isPointers ifTrue: [obj readBinaryContentsFrom: stream manager: self].
  500.     ^obj!
  501.  
  502. getObjectId
  503.     | id |
  504.     ^self at: (id _ stream nextNumber: 3) ifAbsent: [self error: 'non-existant object id']!
  505.  
  506. getTrue
  507.     ^true!
  508.  
  509. nextObject
  510.     | typeByte |
  511.     (typeByte _ stream next) > 127 ifTrue: [
  512.         stream skip: -1.
  513.         ^SmallInteger binaryDefinitionFrom: stream manager: self].
  514.  
  515.     ^self perform: (TypeTable at: typeByte)! !
  516. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  517.  
  518. BinaryInputManager class
  519.     instanceVariableNames: ''!
  520.  
  521.  
  522. !BinaryInputManager class methodsFor: 'structure reading'!
  523.  
  524. readFrom: streamOrFileName
  525.  
  526.     "Reads an object's structure from the stream streamOrFileName
  527.      or the file named streamOrFileName"
  528.  
  529.     (streamOrFileName isKindOf: String)
  530.         ifTrue:
  531.             [^Cursor read showWhile: [(self new: 1024) readFrom: (FileStream fileNamed: streamOrFileName)]].
  532.     ^(self new: 1024) readFrom: streamOrFileName! !
  533.  
  534.  
  535. !FileStream methodsFor: 'testing'!
  536.  
  537. isFileStream
  538.     ^true! !
  539.  
  540.  
  541. !True methodsFor: 'binary storage'!
  542.  
  543. storeBinaryOn: stream manager: manager
  544.     stream nextPut: manager codeForTrue! !
  545.  
  546.  
  547. !SystemDictionary methodsFor: 'binary storage'!
  548.  
  549. addGlobalsTo: globalDictionary manager: manager
  550.     | pools |
  551.     pools _ Set new.
  552.     self associationsDo: [:assoc|
  553.         assoc value isClass
  554.             ifTrue: [
  555.                 assoc value addGlobalsTo: globalDictionary manager: manager.
  556.                 pools addAll: assoc value sharedPools]
  557.             ifFalse: [
  558.                 globalDictionary at: assoc put: self].
  559.         globalDictionary at: assoc value put: self].
  560.  
  561.     pools do: [:poolDictionary|
  562.         poolDictionary addGlobalsTo: globalDictionary manager: manager]!
  563.  
  564. storeBinaryDefinitionOf: anObject on: stream manager: manager
  565.     | string | 
  566.     string _ anObject class == Association
  567.                 ifTrue: ['Smalltalk associationAt: ', anObject key storeString]
  568.                 ifFalse: ['Smalltalk at: ', (self keyAtValue: anObject) storeString].
  569.     stream nextNumber: 2 put: string size.
  570.     string do: [:char| stream nextPut: char asciiValue]! !
  571.  
  572. BinaryIOManager variableSubclass: #BinaryOutputManager
  573.     instanceVariableNames: 'lastIndex globals '
  574.     classVariableNames: ''
  575.     poolDictionaries: ''
  576.     category: 'System-Support'!
  577. BinaryOutputManager comment:
  578. 'Binary storage consists of a sequence of Object IDs
  579.  
  580. Object IDs are identified by 4 byte words.
  581. First byte defines type:
  582.  
  583. byte between: 128 and: 255
  584.         small integer in 31 bits
  585.  
  586. byte = 0        object id in next 3 bytes
  587. byte = 1        nil
  588. byte = 2        true
  589. byte = 3        false
  590. byte = 4        object id in next 3 bytes; object definition follows
  591. byte = 5        class id in next 3 bytes; class definition follows
  592. byte = 6        global id in next 3 bytes; global definition follows
  593.  
  594. Object Definitions are
  595.     class id
  596.     followed by
  597.         non-indexable
  598.             inst size in next byte
  599.             ''inst size'' ids follow
  600.         indexable
  601.             inst size in next byte
  602.             variable size in next 3 bytes
  603.             ''inst size'' ids follow
  604.             ''variable size'' elements follow
  605.  
  606.     see implementors of storeBinaryDefinitionOn:manager: & readBinaryContentsFrom:manager:
  607.  
  608. Class Definitions are
  609.         format in next 2 bytes
  610.         name length in next 2 bytes
  611.         name length bytes of name
  612.  
  613. Global Definitions are
  614.     expression length in next two bytes
  615.     ''expression'' characters follow
  616.  
  617.  
  618. The objects stored as global definitions are collected during BinaryOutputManager>>initialize using the addGlobalsTo:manager: message.  It is possible (hopefully easily) to customize this to add your own globals to the set.'!
  619.  
  620.  
  621. !BinaryOutputManager methodsFor: 'initialize-release'!
  622.  
  623. initialize
  624.     "Initialize my self for subsequent binary output of some object."
  625.     lastIndex _ 0.
  626.     globals _ IdentityDictionary new: 2048.
  627.  
  628.     "Get the system (Smalltalk) to register all objects it considers 'global'
  629.      to the globals table.  Such objects will not be stored; instead an expression
  630.      is stored which (when evaluated) references the global.
  631.      Arbitrary objects may be defined as globals. (use the messages menu item &
  632.      look for implementors of addGlobalsTo:manager:).
  633.     The default is to define as global
  634.         globals in Smalltalk,
  635.         classes,
  636.         class variables & pool variables.
  637.     Collecting the globals takes about 2 seconds. If this is too much time per object
  638.     a default set of globals could be maintained in a class variable"
  639.  
  640.     Smalltalk addGlobalsTo: globals manager: self
  641.  
  642.     "MessageTally spyOn: [(BinaryOutputManager new: 2) initialize]
  643.  
  644.      Time millisecondsToRun: [(BinaryOutputManager new: 2) initialize]"! !
  645.  
  646. !BinaryOutputManager methodsFor: 'accessing'!
  647.  
  648. putIdOf: anObject on: aStream
  649.     | objectId owner |
  650.     anObject hasSpecialBinaryRepresentation ifTrue: [
  651.         ^anObject storeBinaryOn: aStream manager: self].
  652.     nil == (objectId _ self findValueOrNil: anObject)
  653.         ifFalse: [^aStream nextPut: IdType; nextNumber: 3 put: objectId].
  654.     (owner _ globals at: anObject ifAbsent: []) == nil
  655.         ifTrue: [
  656.             self at: anObject put: (lastIndex _ lastIndex + 1).
  657.             aStream
  658.                 nextPut: ObjectType;
  659.                 nextNumber: 3 put: lastIndex.
  660.             anObject storeBinaryDefinitionOn: aStream manager: self]
  661.         ifFalse: [
  662.             anObject isClass ifTrue: [^self putIdOfClass: anObject on: aStream].
  663.             self at: anObject put: (lastIndex _ lastIndex + 1).    
  664.             aStream
  665.                 nextPut: GlobalType;
  666.                 nextNumber: 3 put: lastIndex.
  667.             owner storeBinaryDefinitionOf: anObject on: aStream manager: self]!
  668.  
  669. putIdOfClass: anObject on: aStream
  670.     | classId |
  671.     nil == (classId _ self findValueOrNil: anObject)
  672.         ifFalse: [^aStream nextPut: IdType; nextNumber: 3 put: classId].
  673.     self at: anObject put: (lastIndex _ lastIndex + 1).
  674.     aStream
  675.         nextPut: ClassType;
  676.         nextNumber: 3 put: lastIndex.
  677.     anObject storeBinaryDefinitionOn: aStream manager: self! !
  678.  
  679. !BinaryOutputManager methodsFor: 'private'!
  680.  
  681. findValueOrNil: key  
  682.     "Look for the key in the receiver.  If it is found, answer
  683.     the value corresponding to the key, otherwise answer nil."
  684.  
  685.     | index length probe pass |
  686.     length _ self basicSize.
  687.     pass _ 1.
  688.     index _ key identityHash \\ length + 1.
  689.     [(probe _ self basicAt: index) == nil ifTrue: [^nil].
  690.     probe == key]
  691.         whileFalse: [
  692.             (index _ index + 1) > length ifTrue: 
  693.                 [index _ 1.
  694.                 pass _ pass + 1.
  695.                 pass > 2 ifTrue: [^nil]]].
  696.     ^(valueArray basicAt: index)! !
  697. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  698.  
  699. BinaryOutputManager class
  700.     instanceVariableNames: ''!
  701.  
  702.  
  703. !BinaryOutputManager class methodsFor: 'binary storage'!
  704.  
  705. store: anObject on: aStream
  706.     | manager |
  707.     Cursor wait showWhile: [manager _ (self new: 1024) initialize].
  708.     Cursor write showWhile: [
  709.         (aStream isKindOf: String)
  710.             ifTrue: [
  711.                 | fileStream |
  712.                 fileStream _ FileStream fileNamed: aStream.
  713.                 fileStream binary.
  714.                 anObject storeBinaryOn: fileStream manager: manager.
  715.                 fileStream close]
  716.             ifFalse: [
  717.                 anObject storeBinaryOn: aStream manager: manager]]! !
  718.  
  719.  
  720. !False methodsFor: 'binary storage'!
  721.  
  722. storeBinaryOn: stream manager: manager
  723.     stream nextPut: manager codeForFalse! !
  724.